package com.bondex.charter.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bondex.charter.commons.*;
import com.bondex.charter.dao.CharterBookingMapper;
import com.bondex.charter.dao.CharterSiMapper;
import com.bondex.charter.po.CharterBooking;
import com.bondex.charter.po.CharterUserOperateLogVO;
import com.bondex.charter.pojo.ContainerInfo;
import com.bondex.charter.pojo.DetailPageOutT;
import com.bondex.global.pojo.ResultT;
import com.bondex.global.pojo.TinyException;
import com.bondex.viresult.dto.BondexMailDTO;
import com.bondex.viresult.dto.BookingReleaseDTO;
import com.bondex.viresult.dto.MailMsgResponse;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订舱后台服务
 * Created by JD on 2021/9/16.
 */
@Service
public class BookingService extends BaseService {
    private Logger logger = LoggerFactory.getLogger(BasicDataService.class);

    @Resource
    private CharterBookingMapper charterBookingMapper;
    @Resource
    private CharterSiMapper charterSiMapper;
    /**放舱状态*/
    private static final List<String> strings = Arrays.asList(CharterStatusEnum.BOOKING_NEW.getValueDBString(),
            CharterStatusEnum.BOOKING_PENDING.getValueDBString());
    /**标题*/
    private static final List<String> mailTitles = Arrays.asList(Const.BOOKING_RELEASE_TITLE,
            Const.BOOKING_AMENDMENT_TITLE);
    /**保存状态*/
    private static final List<String> saveStatus = Arrays.asList(CharterStatusEnum.BOOKING_NEW.getValueDBString(),
            CharterStatusEnum.BOOKING_PENDING.getValueDBString(),CharterStatusEnum.BOOKING_RELEASE.getValueDBString());
    @Resource
    private MailUtil mailUtil;
    @Resource
    private UserOperateLogService userOperateLogService;

    /**
     * 获取订舱信息
     */
    public ResultT<DetailPageOutT<CharterBooking, CharterBooking>> getInfo(String orderNo) {
        ResultT<DetailPageOutT<CharterBooking, CharterBooking>> oResult = new ResultT<>(false);
        try {
            if (StringUtils.isBlank(orderNo)) {
                throw new TinyException("入参不可为空。");
            }

            CharterBooking order = charterBookingMapper.selectByOrderNo(orderNo);
            if (null != order && null != order.getContainerInfo()) {
                List<ContainerInfo> containerInfos = JSONObject.parseArray(order.getContainerInfo().toString(), ContainerInfo.class);
                order.setContainerInfos(containerInfos);
            }
            /**订舱待审核状态获取数据更新为待定状态*/
            if (StringUtils.equals(CharterStatusEnum.BOOKING_NEW.toString(), order.getBookingStatus())) {
                order.setBookingStatus(CharterStatusEnum.BOOKING_PENDING.toString());
                List<String> list = new ArrayList<String>();
                charterBookingMapper.updateBookingStatus(list, CharterStatusEnum.BOOKING_PENDING.toString());
            }
            DetailPageOutT<CharterBooking, CharterBooking> data = new DetailPageOutT<>();
            data.setData(order);
            oResult.setSuccess(true);
            oResult.setData(data);
        } catch (Exception e) {
            oResult.setSuccess(false);
            oResult.setMessage(e.getMessage());
        }
        return oResult;
    }

    /**
     * 列表页放舱按钮
     * (只有订舱待审核状态才能点击)
     *
     * @param bookingReleaseDTO
     * @return
     */
    public ResultT releaseShippingSpace(BookingReleaseDTO bookingReleaseDTO) {
        ResultT resultT = new ResultT();
        if (StringUtils.isNotEmpty(bookingReleaseDTO.getTo()) && StringUtils.isNotEmpty(bookingReleaseDTO.getOrderNo())) {
            try {
                String[] arrs = bookingReleaseDTO.getOrderNo().split(",");
                List<String> list = Arrays.asList(arrs);
                List<CharterBooking> charterBookings = charterBookingMapper.selectListByOrderNo(list);
                List<CharterBooking> collect = charterBookings.stream().filter(a -> !strings.contains(a.getBookingStatus())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(collect)) {
                    resultT.setSuccess(false);
                    resultT.setMessage("订舱失败，只有订舱待审核状态才能点击放舱。");
                    return resultT;
                }
                int count = charterBookings.size();
                int success = 0;
                int fail = 0;
                for (CharterBooking booking : charterBookings) {
                    Boolean flag = releaseShippingSpaceByTransactional(booking, bookingReleaseDTO);
                    if (flag) {
                        success++;
                    } else {
                        fail++;
                    }
                }
                resultT.setSuccess(true);
                resultT.setMessage("放舱共：" + count + "条，成功：" + success + "条，失败：" + fail + "条。");
            } catch (Exception e) {
                logger.error("列表页面放舱按钮失败：" + e.getMessage());
                resultT.setSuccess(false);
                resultT.setMessage("列表页面放舱按钮失败！！！");
            }
        } else {
            resultT.setSuccess(false);
            resultT.setMessage("入参不可为空！！！");
        }
        return resultT;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean releaseShippingSpaceByTransactional(CharterBooking booking, BookingReleaseDTO bookingReleaseDTO) {
        Boolean flag = false;
        try {
            MailMsgResponse response = sendMail(booking, bookingReleaseDTO.getCc(), bookingReleaseDTO.getTo(), Const.BOOKING_RELEASE_TITLE, null);
            if(response.getSuccess()){
                charterBookingMapper.updateBookingStatus(Arrays.asList(booking.getOrderNo()), CharterStatusEnum.BOOKING_RELEASE.toString());
                insertCharterUserOperateLog(null, BusinessTypeEnum.BOOKING.getName(), BookingProcessTypeEnum.BOOKING_RELEASE.getName(),
                        JSON.toJSONString(bookingReleaseDTO), null);
                flag = true;
            }
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return flag;
    }


    /**
     * 订舱页面放舱按钮
     * (只有订舱待审核状态才能点击)
     *
     * @param bookingReleaseDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultT releaseShippingSpaceForDetail(BookingReleaseDTO bookingReleaseDTO) {
        ResultT resultT = new ResultT();
        resultT.setSuccess(false);
        resultT.setMessage("放舱失败！！！");
        if (null != bookingReleaseDTO) {
            CharterBooking order = charterBookingMapper.selectByOrderNo(bookingReleaseDTO.getOrderNo());
            try {
                if (!strings.contains(order.getBookingStatus())) {
                    resultT.setSuccess(false);
                    resultT.setMessage("放舱失败，只有订舱待审核,待定状态才能点击放舱。");
                    return resultT;
                }
                order.setGrossWeight(bookingReleaseDTO.getGrossWeight());
                order.setContainerInfo(JSON.toJSONString(bookingReleaseDTO.getContainerInfos()));
                order.setBookingStatus(CharterStatusEnum.BOOKING_RELEASE.getValueDBString());
                MailMsgResponse response = sendMail(order, bookingReleaseDTO.getCc(), bookingReleaseDTO.getTo(), Const.BOOKING_RELEASE_TITLE, null);
                if(response.getSuccess()){
                    charterBookingMapper.updateByPrimaryKey(order);
                    resultT.setSuccess(true);
                    resultT.setMessage("放舱成功！！！");
                    insertCharterUserOperateLog(order, BusinessTypeEnum.BOOKING.getName(), BookingProcessTypeEnum.BOOKING_RELEASE.getName(),
                            JSON.toJSONString(bookingReleaseDTO), JSON.toJSONString(resultT));
                }
            } catch (Exception e) {
                logger.error("明细页面放舱按钮失败：" + e.getMessage());
                resultT.setSuccess(false);
                resultT.setMessage("放舱失败，请联系操作。");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        } else {
            resultT.setSuccess(false);
            resultT.setMessage("入参不可为空！！！");
        }

        return resultT;
    }

    /**
     * 订舱页面保存
     *
     * @param bookingReleaseDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultT saveBookingInfo(BookingReleaseDTO bookingReleaseDTO) {
        ResultT resultT = new ResultT();
        if (null != bookingReleaseDTO) {
            CharterBooking order = charterBookingMapper.selectByOrderNo(bookingReleaseDTO.getOrderNo());
            if(!saveStatus.contains(order.getBookingStatus())){
                resultT.setSuccess(false);
                resultT.setMessage("保存失败，只有订舱待确认/待定/已放舱状态才能点击。");
                return resultT;
            }
            try {
                order.setGrossWeight(bookingReleaseDTO.getGrossWeight());
                order.setContainerInfo(JSON.toJSONString(bookingReleaseDTO.getContainerInfos()));
                charterBookingMapper.updateByPrimaryKey(order);
                resultT.setSuccess(true);
                resultT.setMessage("保存成功！！！");
                insertCharterUserOperateLog(order, BusinessTypeEnum.BOOKING.getName(), BookingProcessTypeEnum.BOOKING_SAVE.getName(),
                        JSON.toJSONString(bookingReleaseDTO), JSON.toJSONString(resultT));
            } catch (Exception e) {
                logger.error("订舱明细页面保存按钮失败：" + e.getMessage());
                resultT.setSuccess(false);
                resultT.setMessage("保存失败，请联系操作。");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        } else {
            resultT.setSuccess(false);
            resultT.setMessage("保存入参不可为空！！！");
        }
        return resultT;
    }

    /**
     * 订舱页面拒绝订舱
     * （除已签发外所有状态，点击更新状态，并发送邮件）
     *
     * @param bookingReleaseDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultT refuseBookingDetail(BookingReleaseDTO bookingReleaseDTO) {
        ResultT resultT = new ResultT();
        resultT.setSuccess(false);
        resultT.setMessage("拒绝订舱失败！！！");
        if (null != bookingReleaseDTO) {
            CharterBooking order = charterBookingMapper.selectByOrderNo(bookingReleaseDTO.getOrderNo());
            if(StringUtils.equals(CharterStatusEnum.SI_BL_RELEASE.getValueDBString(),order.getBookingStatus())){
                resultT.setSuccess(false);
                resultT.setMessage("拒绝订舱失败，已签发状态不允许点击。");
                return resultT;
            }
            try {
                MailMsgResponse response = sendMail(order, bookingReleaseDTO.getCc(), bookingReleaseDTO.getTo(), Const.BOOKING_REJECTION_TITLE, bookingReleaseDTO.getRefusalCause());
                if(response.getSuccess()){
                    charterBookingMapper.updateBookingStatus(Arrays.asList(order.getOrderNo()), CharterStatusEnum.BOOKING_REJECTED.getValueDBString());
                    resultT.setSuccess(true);
                    resultT.setMessage("拒绝订舱成功！！！");
                    insertCharterUserOperateLog(order, BusinessTypeEnum.BOOKING.getName(), BookingProcessTypeEnum.BOOKING_REJECT.getName(),
                            JSON.toJSONString(bookingReleaseDTO), JSON.toJSONString(resultT));
                }
            } catch (Exception e) {
                logger.error("订舱明细页面拒绝订舱按钮失败：" + e.getMessage());
                resultT.setSuccess(false);
                resultT.setMessage("拒绝订舱失败，请联系操作。");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        } else {
            resultT.setSuccess(false);
            resultT.setMessage("拒绝订舱入参不可为空！！！");
        }
        return resultT;
    }

    /**
     * 列表页面拒绝订舱
     * （除已签发外所有状态，点击更新状态，并发送邮件）
     * @param bookingReleaseDTO
     * @return
     */
    public ResultT refuseBooking(BookingReleaseDTO bookingReleaseDTO) {
        ResultT resultT = new ResultT();
        if (StringUtils.isNotEmpty(bookingReleaseDTO.getTo()) && StringUtils.isNotEmpty(bookingReleaseDTO.getOrderNo())) {
            try {
                String[] arrs = bookingReleaseDTO.getOrderNo().split(",");
                List<String> list = Arrays.asList(arrs);
                List<CharterBooking> charterBookings = charterBookingMapper.selectListByOrderNo(list);
                List<CharterBooking> bookingList =charterBookings.stream().filter(a -> StringUtils.equals(CharterStatusEnum.SI_BL_RELEASE.getValueDBString(),
                        a.getBookingStatus())).collect(Collectors.toList());
                if(CollectionUtils.isNotEmpty(bookingList)){
                    resultT.setSuccess(false);
                    resultT.setMessage("拒绝订舱失败，已签发状态不允许点击。");
                    return resultT;
                }
                /**发邮件 存日志记录成功失败条数*/
                int count = charterBookings.size();
                int success = 0;
                int fail = 0;
                for (CharterBooking booking : charterBookings) {
                    Boolean flag = refuseBookingByTransactional(booking, bookingReleaseDTO);
                    if (flag) {
                        success++;
                    } else {
                        fail++;
                    }
                }
                resultT.setSuccess(true);
                resultT.setMessage("拒绝订舱共：" + count + "条，成功：" + success + "条，失败：" + fail + "条。");
            } catch (Exception e) {
                logger.error("列表页面拒绝订舱按钮失败：" + e.getMessage());
                resultT.setSuccess(false);
                resultT.setMessage("列表页面拒绝订舱按钮失败！！！");
            }
        } else {
            resultT.setSuccess(false);
            resultT.setMessage("拒绝订舱入参不可为空！！！");
        }
        return  resultT;
    }
    @Transactional(rollbackFor = Exception.class)
    public Boolean refuseBookingByTransactional(CharterBooking booking, BookingReleaseDTO bookingReleaseDTO) {
        Boolean flag = false;
        try {
            MailMsgResponse response = sendMail(booking, bookingReleaseDTO.getCc(), bookingReleaseDTO.getTo(), Const.BOOKING_REJECTION_TITLE, bookingReleaseDTO.getRefusalCause());
            if(response.getSuccess()){
                charterBookingMapper.updateBookingStatus(Arrays.asList(booking.getOrderNo()),CharterStatusEnum.BOOKING_REJECTED.getValueDBString());
                insertCharterUserOperateLog(booking, BusinessTypeEnum.BOOKING.getName(), BookingProcessTypeEnum.BOOKING_REJECT.getName(),
                        JSON.toJSONString(bookingReleaseDTO), null);
                flag = true;
            }
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return flag;
    }

    /**
     * 退舱
     *（除已签发外所有状态，点击更新状态，并发送邮件）
     * @param bookingReleaseDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultT disembarkBookingForDetail(BookingReleaseDTO bookingReleaseDTO) {
        ResultT resultT = new ResultT();
        resultT.setSuccess(false);
        resultT.setMessage("退舱失败！！！");
        if (null != bookingReleaseDTO) {
            CharterBooking order = charterBookingMapper.selectByOrderNo(bookingReleaseDTO.getOrderNo());
            if(StringUtils.equals(CharterStatusEnum.SI_BL_RELEASE.getValueDBString(),order.getBookingStatus())){
                resultT.setSuccess(false);
                resultT.setMessage("退舱失败，已签发状态不允许点击。");
                return resultT;
            }
            try {
                order.setBookingStatus(CharterStatusEnum.BOOKING_CANCEL.getValueDBString());
                MailMsgResponse response = sendMail(order, bookingReleaseDTO.getCc(), bookingReleaseDTO.getTo(), Const.BOOKING_CANCELLATION_TITLE, bookingReleaseDTO.getRefusalCause());
                if(response.getSuccess()){
                    charterBookingMapper.updateByPrimaryKey(order);
                    resultT.setSuccess(true);
                    resultT.setMessage("退舱成功！！！");
                    insertCharterUserOperateLog(order, BusinessTypeEnum.BOOKING.getName(), BookingProcessTypeEnum.BOOKING_CANCEL.getName(),
                            JSON.toJSONString(bookingReleaseDTO), JSON.toJSONString(resultT));
                }
            } catch (Exception e) {
                logger.error("订舱明细页面退舱按钮失败：" + e.getMessage());
                resultT.setSuccess(false);
                resultT.setMessage("退舱失败，请联系操作。");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        } else {
            resultT.setSuccess(false);
            resultT.setMessage("退舱入参不可为空！！！");
        }
        return resultT;
    }

    /**
     * 列表页退舱
     *(除已签发外所有状态)
     * @param bookingReleaseDTO
     * @return
     */
    public ResultT disembarkBooking(BookingReleaseDTO bookingReleaseDTO) {
        ResultT resultT = new ResultT();
        if (StringUtils.isNotEmpty(bookingReleaseDTO.getTo()) && StringUtils.isNotEmpty(bookingReleaseDTO.getOrderNo())) {
            try {
                String[] arrs = bookingReleaseDTO.getOrderNo().split(",");
                List<String> list = Arrays.asList(arrs);
                List<CharterBooking> charterBookings = charterBookingMapper.selectListByOrderNo(list);
                List<CharterBooking> bookingList =charterBookings.stream().filter(a -> StringUtils.equals(CharterStatusEnum.SI_BL_RELEASE.getValueDBString(),
                        a.getBookingStatus())).collect(Collectors.toList());
                if(CollectionUtils.isNotEmpty(bookingList)){
                    resultT.setSuccess(false);
                    resultT.setMessage("退舱失败，已签发状态不允许点击。");
                    return resultT;
                }
                /**发邮件 存日志记录成功失败条数*/
                int count = charterBookings.size();
                int success = 0;
                int fail = 0;
                for (CharterBooking booking : charterBookings) {
                    Boolean flag = disembarkBookingByTransactional(booking, bookingReleaseDTO);
                    if (flag) {
                        success++;
                    } else {
                        fail++;
                    }
                }
                resultT.setSuccess(true);
                resultT.setMessage("退舱共：" + count + "条，成功：" + success + "条，失败：" + fail + "条。");
            } catch (Exception e) {
                logger.error("列表页面退舱按钮失败：" + e.getMessage());
                resultT.setSuccess(false);
                resultT.setMessage("列表页面退舱按钮失败！！！");
            }
        } else {
            resultT.setSuccess(false);
            resultT.setMessage("退舱入参不可为空！！！");
        }
        return resultT;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean disembarkBookingByTransactional(CharterBooking booking, BookingReleaseDTO bookingReleaseDTO) {
        Boolean flag = false;
        try {
            MailMsgResponse response =sendMail(booking, bookingReleaseDTO.getCc(), bookingReleaseDTO.getTo(), Const.BOOKING_CANCELLATION_TITLE, null);
            if(response.getSuccess()){
                charterBookingMapper.updateBookingStatus(Arrays.asList(booking.getOrderNo()), CharterStatusEnum.BOOKING_CANCEL.getValueDBString());
                insertCharterUserOperateLog(booking, BusinessTypeEnum.BOOKING.getName(), BookingProcessTypeEnum.BOOKING_CANCEL.getName(),
                        JSON.toJSONString(bookingReleaseDTO), null);
                flag = true;
            }
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return flag;
    }

    /**
     * 发送邮件拼装数据
     *
     * @param order 订舱
     * @param cc    抄送人
     * @param to    收件人
     * @param title 邮件标题
     */
    private MailMsgResponse sendMail(CharterBooking order, String cc, String to, String title, String refuseReason) {
        BondexMailDTO bondexMailDTO = new BondexMailDTO();
        bondexMailDTO.setReceiveTo(to);
        bondexMailDTO.setCc(cc);
        if (mailTitles.contains(title)) {
            bondexMailDTO.setId(Const.BOOKING_RELEASE_TEMPLETE_ID);
            bondexMailDTO.setSubject(title + order.getBookingNo() + order.getOrderNo() + order.getContainerNoAndType());
            Map<String, Object> map = new HashMap<>();
            map.put("orderNo", order.getOrderNo());
            map.put("bookingNo", order.getBookingNo()==null?" ":order.getBookingNo());
            map.put("containerNoAndType", order.getContainerNoAndType()==null?" ":order.getContainerNoAndType());
            map.put("vesselAndVoyage", order.getVessel() + " " + order.getVoyage());
            map.put("grossWeight", order.getGrossWeight());
            map.put("portOfLoadingName", order.getPortOfLoadingName());
            map.put("placeOfDeliveryName", order.getPlaceOfDeliveryName());
            map.put("etd", order.getEtd()==null?" ":order.getEtd());
            map.put("siCutOff", order.getSiCutOff()==null?" ":order.getSiCutOff());
            map.put("cyCutOff", order.getCyCutOff()==null?" ":order.getCyCutOff());
            map.put("description", order.getDescription());
            bondexMailDTO.setVariableContext(map);
        }
        if (StringUtils.equals(Const.BOOKING_REJECTION_TITLE, title)) {
            bondexMailDTO.setId(Const.BOOKING_REJECTION_TEMPLETE_ID);
            bondexMailDTO.setSubject(title + order.getBookingNo() + order.getOrderNo() + order.getContainerNoAndType());
            Map<String, Object> map = new HashMap<>();
            map.put("orderNo", order.getOrderNo()==null?" ":order.getOrderNo());
            map.put("refuseReason", refuseReason==null?" ":refuseReason);
            bondexMailDTO.setVariableContext(map);
        }
        if (StringUtils.equals(Const.BOOKING_CANCELLATION_TITLE, title)) {
            bondexMailDTO.setId(Const.BOOKING_CANCELLATION_TEMPLETE_ID);
            bondexMailDTO.setSubject(title + order.getBookingNo() + order.getOrderNo() + order.getContainerNoAndType());
            Map<String, Object> map = new HashMap<>();
            map.put("orderNo", order.getOrderNo()==null?" ":order.getOrderNo());
            map.put("bookingNo", order.getBookingNo()==null?" ":order.getBookingNo());
            map.put("remark", refuseReason);
            bondexMailDTO.setVariableContext(map);
        }
        MailMsgResponse response = mailUtil.pushMail(bondexMailDTO);
        return response;
    }

    /**
     * 组装日志实体
     *
     * @param order        订舱实体
     * @param businessType 业务类型
     * @param processType  操作类型
     * @param requestInfo  入参
     * @param responseInfo 出参
     */
    private void insertCharterUserOperateLog(CharterBooking order, String businessType, String processType, String requestInfo, String responseInfo) {
        CharterUserOperateLogVO charterUserOperateLogVO = new CharterUserOperateLogVO();
        charterUserOperateLogVO.setBusinessType(businessType);
        charterUserOperateLogVO.setProcessType(processType);
        charterUserOperateLogVO.setRequestInfo(requestInfo);
        charterUserOperateLogVO.setResponseInfo(responseInfo);
        charterUserOperateLogVO.setBookingNo(order.getBookingNo());
        charterUserOperateLogVO.setBlNo(order.getBlNo());
        charterUserOperateLogVO.setCustomerNo(order.getCustomerNo());
        charterUserOperateLogVO.setCreateBy("admin");
        charterUserOperateLogVO.setCreateDate(new Date());
        userOperateLogService.insertCharterUserOperateLog(charterUserOperateLogVO);
    }
}
